home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Programming / MuManual / C_Sources / MuRemapTest.c < prev    next >
C/C++ Source or Header  |  1999-05-26  |  22KB  |  603 lines

  1. /*************************************************
  2.  ** MuRemapTest                                 **
  3.  ** experimental MMU memory remapper            **
  4.  **                                             **
  5.  ** This program checks for correctness of the  **
  6.  ** device drivers and correct MMU support      **
  7.  **                                             **
  8.  ** Note that device drivers have to call       **
  9.  ** CachePreDMA() and CachePostDMA() to be      **
  10.  ** notified about the TRUE physical addresses  **
  11.  ** some devices might fail here                **
  12.  **                                             **
  13.  ** Version 40.0        26 May 1999             **
  14.  ** © THOR Thomas Richter                       **
  15.  *************************************************/
  16.  
  17. /// Includes
  18. #include <exec/types.h>
  19. #include <exec/memory.h>
  20. #include <exec/ports.h>
  21. #include <exec/execbase.h>
  22. #include <dos/dos.h>
  23.  
  24. /* MMU specific includes */
  25. #include <mmu/mmubase.h>
  26. #include <mmu/context.h>
  27. #include <mmu/mmutags.h>
  28.  
  29. #include <workbench/startup.h>
  30.  
  31. #include <proto/exec.h>
  32. #include <proto/mmu.h>
  33. #include <proto/dos.h>
  34. #include <proto/icon.h>
  35. #include <string.h>
  36. ///
  37. /// Defines
  38. #define STRINGDATE "5.3.99"
  39. #define STRINGVERSION "40.0"
  40.  
  41. /* Defines for the shell template */
  42. #define TEMPLATE "TEMPFILE/A"
  43.  
  44. #define OPT_DEVICE 0
  45. #define OPT_WINDOW 1
  46. #define OPT_COUNT 2
  47. ///
  48. /// Statics
  49.  
  50. /* just the library bases */
  51. struct MMUBase *MMUBase;
  52. struct DosLibrary *DOSBase;
  53. struct ExecBase *SysBase;
  54. struct Library *IconBase;
  55. ///
  56. /// Protos
  57.  
  58. /* prototyping */
  59. int __asm __saveds main(void);
  60. struct RDArgs *ReadTTArgs(struct WBStartup *msg,LONG args[],struct RDArgs **tmp);
  61. int CheckRemapping(char *filename);
  62. BOOL SetRemap(struct MMUContext *ctx,struct MemHeader *physical,struct MemHeader *logical,ULONG size);
  63. void FileTest(char *filename,void *physical,void *logical,ULONG size);
  64. BOOL ForceRebuild(struct MMUContext *ctx);
  65. struct MemHeader *MemHeaderOf(void *mem);
  66. ///
  67.  
  68. char version[]="$VER: MuRemapTest " STRINGVERSION " (" STRINGDATE ") © THOR";
  69.  
  70. /// main
  71. int __asm __saveds main(void)
  72. {
  73. LONG args[OPT_COUNT];
  74. struct RDArgs *rd,*myrd;
  75. struct Process *proc;
  76. int rc=20;
  77. LONG err;
  78. struct WBStartup *msg;
  79. BPTR oldout;
  80. struct MsgPort *oldconsole;
  81.  
  82.  
  83.         /* This program is compiled without startup code, hence we have
  84.            to setup ourselfs */
  85.  
  86.         SysBase=*((struct ExecBase **)(4L));
  87.  
  88.         /* clear the arguments */
  89.         memset(args,0,sizeof(LONG)*OPT_COUNT);
  90.  
  91.         /* Wait for the workbench startup, if any */
  92.         proc=(struct Process *)FindTask(NULL);
  93.  
  94.         if (!(proc->pr_CLI)) {
  95.                 WaitPort(&(proc->pr_MsgPort));
  96.                 msg=(struct WBStartup *)GetMsg(&(proc->pr_MsgPort));
  97.         } else  msg=NULL;
  98.  
  99.  
  100.         /* Open the libraries we need */
  101.  
  102.         if (DOSBase=(struct DosLibrary *)OpenLibrary("dos.library",37L)) {
  103.                 if (MMUBase=(struct MMUBase *)OpenLibrary("mmu.library",0L)) {
  104.  
  105.                         err=ERROR_REQUIRED_ARG_MISSING;
  106.  
  107.                         myrd=NULL;      /* reset the temporary ReadArgs */
  108.                         oldout=NULL;
  109.                         oldconsole=NULL;
  110.  
  111.                         /* Check whether we're run from workbench or
  112.                            shell. On a WBRun, we parse the tool types
  113.                            and setup our own output stream, keeping
  114.                            the old one - which will be NULL anyways... */
  115.  
  116.                         if (msg) {
  117.                                 oldout=SelectOutput(NULL);
  118.                                 oldconsole=SetConsoleTask(NULL);
  119.                                 rd=ReadTTArgs(msg,args,&myrd);
  120.                         } else  rd=ReadArgs(TEMPLATE,args,NULL);
  121.  
  122.                         if (rd) {
  123.  
  124.                                 /* Check for a working MMU. The mmu library
  125.                                    will open anyways, even without one. */
  126.  
  127.                                 if (!GetMMUType()) {
  128.                                         Printf("MuRemapTest requires a working MMU.\n");
  129.                                         err=10;
  130.                                 } else {
  131.                                         /* Argument parser worked, call main routine */
  132.                                         err=CheckRemapping((char *)(args[OPT_DEVICE]));
  133.                                 }
  134.  
  135.                                 /* Shut down */
  136.  
  137.                                 FreeArgs(rd);
  138.                                 if (myrd) FreeDosObject(DOS_RDARGS,myrd);
  139.                                 if (msg)  Close(SelectOutput(NULL));
  140.                         } else  err=IoErr();
  141.  
  142.                         if (msg) {
  143.                                 SelectOutput(oldout);
  144.                                 SetConsoleTask(oldconsole);
  145.                         }
  146.  
  147.                         /* we're done. Check for the result code. If
  148.                            it is below 64, it is passed over as primary
  149.                            result code. */
  150.  
  151.                         if (err<64) {
  152.                                 rc=err;
  153.                                 err=0;
  154.                         } else {
  155.                                 if (!msg) PrintFault(err,"MuRemapTest failed");
  156.                                 rc=10;
  157.                         }
  158.                         SetIoErr(err);
  159.  
  160.                         CloseLibrary((struct Library *)MMUBase);
  161.                 } else PrintFault(ERROR_OBJECT_NOT_FOUND,"MuRemapTest requires the mmu.library");
  162.                 CloseLibrary((struct Library *)DOSBase);
  163.         }
  164.  
  165.         return rc;
  166. }
  167. ///
  168. /// ReadTTArgs
  169. struct RDArgs *ReadTTArgs(struct WBStartup *msg,LONG args[],struct RDArgs **tmp)
  170. {
  171. struct WBArg *wbarg;
  172. struct DiskObject *dop;
  173. char **tt;                      /* ToolTypes array */
  174. char *wbstr;                    /* Our self-made workbench argument string */
  175. char *here;
  176. BPTR oldlock;
  177. ULONG len;
  178. struct RDArgs *rd=NULL,*myrd=NULL;
  179. LONG err=0;
  180. BPTR newout;
  181.  
  182.  
  183.         /* Parse the tool type string for arguments...
  184.            this is mainly Mike's code. */
  185.  
  186.         if (IconBase=OpenLibrary("icon.library",37L)) {
  187.                 if (wbarg=msg->sm_ArgList) {
  188.                         /* use a project icon if there is one... */
  189.                         if (msg->sm_NumArgs > 1) wbarg++;
  190.  
  191.                         /* go into the directory */
  192.                         oldlock=CurrentDir(wbarg->wa_Lock);
  193.  
  194.                         if (dop=GetDiskObject(wbarg->wa_Name)) {
  195.                                 if (tt=dop->do_ToolTypes) {
  196.                                         /* Read a special tool type for the output window */
  197.  
  198.                                         /* Calc the size of the argument string */
  199.  
  200.                                         len = 3;        /* reserve space for SPC,LF,NUL */
  201.                                         while (*tt) {
  202.                                                 len += strlen(*tt)+1;   /* string, plus space */
  203.                                                 tt++;
  204.                                         }
  205.  
  206.                                         if (wbstr=AllocVec(len,MEMF_PUBLIC)) {
  207.                                                 /* Now copy the arguments into this string, one by one
  208.                                                    and check whether the argument string is still valid. */
  209.  
  210.                                                 tt=dop->do_ToolTypes;
  211.                                                 here=wbstr;
  212.                                                 do{
  213.                                                         *here='\0';                     /* terminate string */
  214.                                                         /* Check whether this tool type is
  215.                                                            commented out. Just ignore it in this case */
  216.                                                         if (*tt) {
  217.                                                                 if (**tt=='(' || **tt==';')
  218.                                                                         continue;
  219.  
  220.                                                                 strcpy(here,*tt);      /* Add TT string */
  221.                                                         }
  222.                                                         len=strlen(here);
  223.                                                         here[len]='\n';
  224.                                                         here[len+1]='\0';               /* terminate string */
  225.  
  226.                                                         /* Now try to ReadArg' this string */
  227.  
  228.                                                         /* release old arguments left over from last loop */
  229.                                                         if (rd) FreeArgs(rd);
  230.                                                         if (myrd) FreeDosObject(DOS_RDARGS,myrd);
  231.                                                         rd=NULL;
  232.                                                         memset(args,0,sizeof(LONG)*OPT_COUNT);
  233.  
  234.                                                         if (myrd=AllocDosObject(DOS_RDARGS,NULL)) {
  235.                                                                 /* Allocate and setup the ReadArgs source */
  236.                                                                 myrd->RDA_Source.CS_Buffer=wbstr;
  237.                                                                 myrd->RDA_Source.CS_Length=strlen(wbstr);
  238.  
  239.                                                                 if (rd=ReadArgs(TEMPLATE ",WINDOW/K",args,myrd)) {
  240.                                                                         /* Is this still valid? */
  241.                                                                         here[len]=' ';
  242.                                                                         here+=len+1;
  243.                                                                         /* if so, accept this argument and go on */
  244.                                                                 } else {
  245.                                                                         err=IoErr();
  246.                                                                         if (err==ERROR_NO_FREE_STORE) break;
  247.                                                                         else    err=0;  /* Ignore unknown or invalid arguments silently */
  248.                                                                 }
  249.                                                         } else {
  250.                                                                 err=ERROR_NO_FREE_STORE;
  251.                                                                 break;
  252.                                                         }
  253.                                                 }while(*tt++);
  254.  
  255.                                                 FreeVec(wbstr);
  256.                                         } else err=ERROR_NO_FREE_STORE;
  257.                                 } else err=ERROR_REQUIRED_ARG_MISSING; /* Huh, how should this happen ? */
  258.                                 FreeDiskObject(dop);
  259.                         } else err=IoErr();
  260.                         CurrentDir(oldlock);
  261.                 } else err=ERROR_REQUIRED_ARG_MISSING; /* This should not happen either */
  262.                 CloseLibrary(IconBase);
  263.         } else err=ERROR_OBJECT_NOT_FOUND;    /* This should not happen */
  264.  
  265.         /* Open an output stream */
  266.  
  267.         if (err==0) {
  268.                 if (newout=Open((args[OPT_WINDOW])?((char *)args[OPT_WINDOW]):("NIL:"),MODE_NEWFILE)) {
  269.                         SelectOutput(newout);
  270.                         /* Hack in the output console. Well, well... */
  271.                         SetConsoleTask(((struct FileHandle *)(BADDR(newout)))->fh_Type);
  272.                 } else err=IoErr();
  273.         }
  274.  
  275.         if (err) {
  276.                 if (rd)   FreeArgs(rd);
  277.                 if (myrd) FreeDosObject(DOS_RDARGS,myrd);
  278.                 SetIoErr(err);
  279.                 rd=NULL;
  280.                 myrd=NULL;
  281.         }
  282.  
  283.         *tmp=myrd;
  284.         return rd;
  285. }
  286. ///
  287. /// CheckRemapping
  288. int CheckRemapping(char *testfile)
  289. {
  290. struct MMUContext *ctx,*sctx;   /* default context, supervisorcontext */
  291. ULONG psize,ssize;
  292. ULONG largest;
  293. struct MemHeader *mem,*oldheader,*dest;
  294.  
  295.         /* This is the main routine. It mirrors RAM to somehwere else
  296.            and tries to write it to disk. If this fails, the disk
  297.            driver is misdesigned because it fails to call
  298.            the CachePre/PostDMA functions. Yuck! */
  299.  
  300.         ctx=DefaultContext();   /* get the default context */
  301.         sctx=SuperContext(ctx); /* get the supervisor context for this one */
  302.  
  303.         psize=RemapSize(ctx);
  304.         ssize=RemapSize(sctx);
  305.         if (ssize>psize)
  306.                 psize=ssize;    /* Largest required alignment. Well
  307.                                    actually, the two should be identically,
  308.                                    usually. */
  309.  
  310.         Forbid();
  311.  
  312.         /* Get a huge memory block. The largest available, but only the
  313.            half of it. */
  314.  
  315.         largest=AvailMem(MEMF_FAST|MEMF_PUBLIC|MEMF_LARGEST)>>1;
  316.         largest &= -(LONG)psize;
  317.  
  318.         /* and allocate what remains after correct alignment */
  319.  
  320.         if (largest)    mem=AllocAligned(largest,MEMF_FAST|MEMF_PUBLIC,psize);
  321.         else            mem=NULL;
  322.         Permit();
  323.  
  324.         if (mem==NULL) {
  325.                 return ERROR_NO_FREE_STORE;
  326.         }
  327.  
  328.  
  329.         /* mirror this memory to below 0x80000000 */
  330.  
  331.         dest=(struct MemHeader *)(0x80000000-largest);        /* remap memory to top area */
  332.  
  333.         /* And remap it */
  334.         if (!SetRemap(ctx,mem,dest,largest)) {
  335.                 return ERROR_NO_FREE_STORE;
  336.         }
  337.  
  338.         /* For the supervisor as well */
  339.  
  340.         if (!SetRemap(sctx,mem,dest,largest)) {
  341.                 if (!SetRemap(ctx,mem,NULL,largest))    /* Ouch! Can't restore! */
  342.                         Alert(0x3e020000);
  343.                 return ERROR_NO_FREE_STORE;
  344.         }
  345.  
  346.         /* Run the file test */
  347.         FileTest(testfile,(void *)mem,(void *)dest,largest);
  348.         DeleteFile(testfile);
  349.  
  350.         /* Now initialize this memory as fast and setup a MemHeader */
  351.         Forbid();
  352.         dest->mh_Node.ln_Pri=64;                /* Use this first */
  353.         dest->mh_Node.ln_Type=NT_MEMORY;
  354.         dest->mh_Attributes=MEMF_FAST|MEMF_PUBLIC;
  355.         dest->mh_Lower=(APTR)(((UBYTE *)dest)+sizeof(struct MemHeader));
  356.         dest->mh_Upper=(APTR)(0x80000000);
  357.         dest->mh_First=(struct MemChunk *)(dest->mh_Lower);
  358.         dest->mh_First->mc_Next=NULL;
  359.         dest->mh_First->mc_Bytes=((UBYTE *)(dest->mh_Upper))-((UBYTE *)(dest->mh_Lower));
  360.         dest->mh_Free=dest->mh_First->mc_Bytes;
  361.         oldheader=MemHeaderOf(mem);
  362.         dest->mh_Node.ln_Name=oldheader->mh_Node.ln_Name;
  363.  
  364.         /* I don't use AddMem here because this is hacked by Ralphie. */
  365.         Enqueue(&(SysBase->MemList),&(dest->mh_Node));
  366.         oldheader->mh_Attributes &= ~(MEMF_PUBLIC);
  367.         Permit();
  368.  
  369.         /* Force rebuilding this property list to test the MMU table
  370.            allocation */
  371.         ForceRebuild(ctx);
  372.         Delay(50L);
  373.  
  374.         /* Since the system allocates now memory from this new public
  375.            header, we can't exit here safely! Say bye, bye! */
  376.  
  377.         Printf("Now just work with your system. Everything should behaive\n"
  378.                "normal, provided the previous test worked! In case it didn't\n"
  379.                "please reboot now or you risk your HD! There is\n"
  380.                "no exit here, unfortunately.\n");
  381.  
  382.         /* sigh */
  383.         Wait(0L);
  384.  
  385.  
  386.         /* This is how it *should* work, provided none of our faked memory
  387.            is allocated */
  388.  
  389.         Forbid();
  390.         /* Make this public again */
  391.         oldheader->mh_Attributes |= MEMF_PUBLIC;
  392.         /* Lower the priority of this pool again */
  393.         dest->mh_Node.ln_Pri=-128;
  394.         dest->mh_Attributes &= ~(MEMF_PUBLIC);
  395.         Remove(&(dest->mh_Node));
  396.         /* Add it again to the memory list */
  397.         Enqueue(&(SysBase->MemList),&(dest->mh_Node));
  398.         Permit();
  399.  
  400.         /* Again, to the old location */
  401.         ForceRebuild(ctx);
  402.  
  403.         /* This will hopefully release all the memory allocated from
  404.            this pool. It's only a test, anyways... */
  405.  
  406.         /* Un-do the relocation */
  407.  
  408.         if (!SetRemap(sctx,mem,NULL,largest)) {
  409.                 Alert(0x3e020000);
  410.                 return ERROR_NO_FREE_STORE;
  411.         }
  412.  
  413.         if (!SetRemap(ctx,mem,NULL,largest)) {
  414.                 Alert(0x3e020000);
  415.                 return ERROR_NO_FREE_STORE;
  416.         }
  417.  
  418.         /* Free the private pool */
  419.         Forbid();
  420.         Remove(&(mem->mh_Node));
  421.         Permit();
  422.  
  423.         FreeMem(mem,largest);
  424.  
  425.         return 0;
  426. }
  427. ///
  428. /// SetRemap
  429. BOOL SetRemap(struct MMUContext *ctx,struct MemHeader *physical,struct MemHeader *logical,ULONG size)
  430. {
  431. struct MinList *ctxl;
  432. ULONG new;
  433.  
  434.         /* remap a memory block to a different position, using the MMU
  435.            library */
  436.         if (logical) {
  437.                 new=MAPP_REMAPPED|MAPP_COPYBACK;
  438.         } else  new=MAPP_REPAIRABLE|MAPP_INVALID;
  439.  
  440.         /* Make a backup of the current mapping */
  441.         if (ctxl=GetMapping(ctx)) {
  442.                 /* remap it */
  443.                 if (SetProperties(ctx,new,~0,(ULONG)logical,size,MAPTAG_DESTINATION,(ULONG)physical,TAG_DONE)) {
  444.                         /* and rebuild the MMU tree */
  445.                         if (RebuildTree(ctx)) {
  446.                                 /* if this worked, release the backup */
  447.                                 ReleaseMapping(ctx,ctxl);
  448.                                 return TRUE;
  449.                         }
  450.                 }
  451.                 /* if it did not work, restore the backup */
  452.                 SetPropertyList(ctx,ctxl);
  453.                 ReleaseMapping(ctx,ctxl);
  454.         }
  455.  
  456.         return FALSE;
  457. }
  458. ///
  459. /// FileTest
  460. void FileTest(char *filename,void *physical,void *logical,ULONG size)
  461. {
  462. BPTR file;
  463. UWORD buffer;
  464. UWORD *buf;
  465. ULONG i;
  466.  
  467.         /* This runs a stupid test to check whether the device really
  468.            knows about the MMU. A correctly written device should call
  469.            CachePreDMA() and CachePostDMA() to get the physical address
  470.            from the logical address. */
  471.  
  472.         Printf("Running the filing system MMU awarenest tests.\n");
  473.  
  474.  
  475.         /* Limit this to 64K */
  476.         if (size>65536)
  477.                 size=65536;
  478.  
  479.         file=Open(filename,MODE_NEWFILE);
  480.  
  481.         if (!file) {
  482.                 PrintFault(IoErr(),"MuRemapTest failed to open the tempfile");
  483.                 return;
  484.         }
  485.  
  486.         /* Fill the buffer with a write pattern */
  487.         for(buf=(UWORD *)logical,i=size>>1;i;i--,buf++) {
  488.                 *buf=i;
  489.         }
  490.  
  491.         /* Now write the pattern */
  492.         Printf("Running the write test.\n");
  493.         if (Write(file,logical,size)!=size) {
  494.                 PrintFault(IoErr(),"Failed writing the test pattern");
  495.                 Close(file);
  496.                 return;
  497.         }
  498.  
  499.         /* Done writing the data */
  500.         Close(file);
  501.  
  502.         /* Now check for the pattern, reading byte for byte */
  503.  
  504.         file=Open(filename,MODE_OLDFILE);
  505.         if (!file) {
  506.                 PrintFault(IoErr(),"MuRemapTest failed to reopen the tempfile");
  507.                 return;
  508.         }
  509.  
  510.         /* Now read the data, word by word */
  511.         for(i=size>>1;i;i--) {
  512.                 if (Read(file,&buffer,sizeof(UWORD))!=sizeof(UWORD)) {
  513.                         PrintFault(IoErr(),"MuRemapTest failed to re-read the data");
  514.                         Close(file);
  515.                         return;
  516.                 }
  517.                 if (buffer!=i) {
  518.                         Printf("The write test failed, the device is not MMU aware.\n");
  519.                         Close(file);
  520.                         return;
  521.                 }
  522.         }
  523.  
  524.         Close(file);
  525.         Printf("The write test passed.\n");
  526.  
  527.         /* Now try again reading it back as a whole */
  528.  
  529.         file=Open(filename,MODE_OLDFILE);
  530.         if (!file) {
  531.                 PrintFault(IoErr(),"MuRemapTest failed to reopen the tempfile");
  532.                 return;
  533.         }
  534.  
  535.         /* Fill the memory area with zeros */
  536.         memset(logical,0,(size_t)size);
  537.         /* Really! */
  538.         CacheClearU();
  539.  
  540.         /* Read in one big block. This should use DMA again. */
  541.  
  542.         Printf("Now running the read test.\n");
  543.         if (Read(file,logical,size)!=size) {
  544.                 PrintFault(IoErr(),"MuRemapTest failed to re-read the tempfile");
  545.                 Close(file);
  546.         }
  547.  
  548.         Close(file);
  549.  
  550.         /* Compare the read data */
  551.         for(buf=(UWORD *)logical,i=size>>1;i;i--,buf++) {
  552.                 if (*buf!=i) {
  553.                         Printf("The read test failed.\n");
  554.                         return;
  555.                 }
  556.         }
  557.  
  558.         Printf("All tests passed.\n");
  559.  
  560. }
  561. ///
  562. /// MemHeaderOf
  563. struct MemHeader *MemHeaderOf(void *mem)
  564. {
  565. struct MemHeader *mh;
  566. ULONG adr;
  567. ULONG lower,upper;
  568.  
  569.         /* Find the memory header of a given address.
  570.            This MUST be called in FORBID state. */
  571.  
  572.         adr=(ULONG)mem;
  573.  
  574.         for(mh=(struct MemHeader *)(SysBase->MemList.lh_Head);mh->mh_Node.ln_Succ;mh=(struct MemHeader *)(mh->mh_Node.ln_Succ)) {
  575.                 lower=(ULONG)(mh->mh_Lower);
  576.                 upper=(ULONG)(mh->mh_Upper);
  577.                 if (adr>=lower && adr<upper)
  578.                         return mh;
  579.         }
  580.  
  581.         return NULL;
  582. }
  583. ///
  584. /// ForceRebuild
  585. BOOL ForceRebuild(struct MMUContext *ctx)
  586. {
  587. struct MinList *ctxl;
  588.  
  589.         /* Force a complete rebuild of the MMU tree */
  590.  
  591.         if (ctxl=GetMapping(ctx)) {
  592.                 TouchPropertyList(ctxl);        /* This is intentionally undocumented */
  593.                 SetPropertyList(ctx,ctxl);
  594.                 ReleaseMapping(ctx,ctxl);
  595.                 if (RebuildTree(ctx))
  596.                         return TRUE;
  597.         }
  598.  
  599.         return FALSE;
  600. }
  601. ///
  602.  
  603.